#ifndef MINIBSPLINESURFACE_H
#define MINIBSPLINESURFACE_H

#include "MiniObject.h"

namespace XYF
{
    /**
     * @file: MiniBSplineSurface.h
     * @author: xingyifan
     * @date: 2023-03-16 15:18
     *
     * @description: B 样条曲面
     */

    class MiniBSplineSurface : public MiniObject
    {
    public:
        // 标准构造函数
        MiniBSplineSurface(const MiniArray2D<Vector3f> &cpts,
                           const MiniArray<Real> &uKnots,
                           const MiniArray<Real> &vKnots,
                           const int uDegree,
                           const int vDegree,
                           const bool uPeriodic = false,
                           const bool vPeriodic = false);

        // 构造均匀样条（均非周期）
        MiniBSplineSurface(const int Nu,
                           const int Nv,
                           const int uDegree,
                           const int vDegree);

        // 重载返回类型
        virtual int GetType() override;

        const MiniArray2D<Vector3f> &GetPoints() const; // 获得顶点数组的引用
        MiniArray2D<Vector3f> &GetPoints();             // 获得顶点数组
        int GetUPointsNum() const;                      // 获得 u 方向顶点数
        int GetVPointsNum() const;                      // 获得 v 方向顶点数
        int GetUDegree() const;                         // 获得 u 方向次数
        int GetVDegree() const;                         // 获得 v 方向次数
        bool GetUPeriodic() const;                      // 获得 u 方向是否周期
        bool GetVPeriodic() const;                      // 获得 v 方向是否周期
        MiniArray<Real> GetUKnots() const;              // 获得 u 方向节点
        MiniArray<Real> GetVKnots() const;              // 获得 v 方向节点
        MiniArray<Real> &GetUKnots();                   // 获得 u 方向节点的引用
        MiniArray<Real> &GetVKnots();                   // 获得 v 方向节点的引用
        Real GetUBegin() const;                         // 获得 u 方向起始参数
        Real GetVBegin() const;                         // 获得 v 方向起始参数
        Real GetUEnd() const;                           // 获得 u 方向终止参数
        Real GetVEnd() const;                           // 获得 v 方向终止参数

        Vector3f SurfacePoint(Real u, Real v) const;                                         // 计算参数 u,v 处的点
        MiniArray4D<Vector3f> SurfaceDerivCpts(int d, int r1, int r2, int s1, int s2) const; // 计算指定范围不大于 d 阶导数的控制点
        MiniArray2D<Vector3f> SurfaceDerivPoint(int d, Real u, Real v) const;                // 计算不大于 d 阶 偏导数曲线在 u,v 处的点

        void SurfaceKnotIns(Real t, int r, char para);                      // 节点插入算法：在 para 方向将 t 插入 r 次
        void SurfaceRefineKnot(const MiniArray<Real> &X, char para);        // 节点优化算法：将递增序列 X 中的节点插入
        Vector NearPointProjection(Vector3f P, Vector uv, Real tol);        // 以 uv 为初始迭代参数，返回 P 在曲面上的最近距离投影点的参数，误差不大于 tol
        Vector OrthoPointProjection(Vector3f P, Vector uv, Real tol);       // 以 uv 为初始迭代参数，返回 P 在曲面上的正交投影，误差不超过 tol
        Vector OrthoPointTorusProjection(Vector3f P, Vector uv, Real tol);  // 以 uv 为初始迭代参数，返回 P 在曲面上的正交投影，误差不超过 tol

    protected:
        MiniArray2D<Vector3f> m_cpts;
        MiniArray<Real> m_uKnots;
        MiniArray<Real> m_vKnots;
        int m_uDegree;
        int m_vDegree;
        bool m_uPeriodic;
        bool m_vPeriodic;
    };
}

#endif // MINIBSPLINESURFACE_H
